import { Toaster } from "sonner";
import { createPortal } from "react-dom";
import {
  CSSProperties,
  forwardRef,
  StrictMode,
  useEffect,
  useState,
} from "react";
import MUiTheme from "./components/MuiTheme";
import { Tooltip } from "@mui/material";
import Home from "./views/Home";
import useDragable from "./lib/hooks/useDragable";
import LogoIcon from "@/assets/images/Logo.png";
import CloseIcon from "@/assets/icons/close.svg?jsx";
import useMergeRefs from "./lib/hooks/useMergeRefs";
import clsm from "./lib/utils/clsm";
import debounce from "./lib/utils/debounce";
import { useIsMobile } from "./lib/hooks/useMediaQuery";

export default function App() {
  const [open, setOpen] = useState(false);

  return createPortal(
    <StrictMode>
      <MUiTheme>
        <div className="group/yh-qa">
          <div className="pointer-events-none fixed top-0 !z-[9999] flex h-screen w-screen items-center justify-end pt-[50px] *:pointer-events-auto md:inset-0 md:pt-0">
            {!open && (
              <Tooltip title="云瀚知识库助手" placement="left" arrow>
                <DragableButton onClick={() => setOpen(true)} />
              </Tooltip>
            )}
            {open && <DragableDialog onClickClose={() => setOpen(false)} />}
          </div>
        </div>
      </MUiTheme>
      <Toaster position="top-center" theme="system" richColors />
    </StrictMode>,
    document.body,
  );
}

type DragableButtonProps = {
  onClick: () => void;
  className?: string;
  style?: CSSProperties;
};
const getInitialButtonOffset = () =>
  JSON.parse(
    localStorage.getItem("yhqa-button-offset") || '{"left":0,"top":0}',
  ) as { top: number; left: number };
const debounceSave = debounce(function (position: {
  top: number;
  left: number;
}) {
  localStorage.setItem("yhqa-button-offset", JSON.stringify(position));
});
const DragableButton = forwardRef<HTMLButtonElement, DragableButtonProps>(
  function DragableButton(props, ref) {
    const { onClick, className, style, ...rest } = props;
    const {
      ref: dRef,
      offset,
      isDragging,
    } = useDragable<HTMLButtonElement>({
      mode: "drag",
      initialOffset: getInitialButtonOffset,
      forceViewport: true,
      onDragStart(el) {
        el.style.transition = "";
      },
      onDragEnd(el, offset, updateOffset) {
        requestAnimationFrame(() => {
          updateOffset({ ...offset, left: 0 });
          el.style.transition = "left 0.3s ease";
          el.addEventListener("transitionend", (e) => {
            if (e.propertyName === "left") {
              el.style.transition = "";
            }
          });
        });
      },
    });
    const mergedRef = useMergeRefs(dRef, ref);

    useEffect(() => {
      debounceSave(offset);
    }, [offset]);

    return (
      <button
        className={clsm(
          className,
          "!border-none !bg-transparent p-2 !outline-none",
        )}
        style={{
          ...style,
          ...offset,
          position: "relative",
          transition: isDragging ? "none" : undefined,
        }}
        onClick={onClick}
        ref={mergedRef}
        {...rest}
      >
        <img
          src={LogoIcon}
          className="size-11 transition-transform hover:scale-110"
        />
      </button>
    );
  },
);

type DragableDialogProps = {
  onClickClose: () => void;
};
const getInitialDialogTransform = () =>
  JSON.parse(
    localStorage.getItem("yhqa-dialog-position") || '{"top":0,"left":0}',
  ) as { top: number; left: number };
const debounceSaveDialog = debounce(function (position: {
  top: number;
  left: number;
}) {
  localStorage.setItem("yhqa-dialog-position", JSON.stringify(position));
});

function DragableDialog(props: DragableDialogProps) {
  const { onClickClose } = props;
  const isMobile = useIsMobile();
  const { ref, forceElementRef, offset, isDragging } = useDragable<
    HTMLDivElement,
    HTMLDivElement
  >({
    mode: "click",
    initialOffset: getInitialDialogTransform,
    enable: !isMobile,
    forceViewport: true,
    onDragStart(el) {
      el.style.transition = "";
    },
  });

  useEffect(() => {
    debounceSaveDialog(offset);
  }, [offset]);

  return (
    <div
      style={
        isMobile
          ? undefined
          : {
              ...offset,
              position: "relative",
              transition: isDragging ? "none" : undefined,
            }
      }
      className="flex h-full flex-col overflow-auto bg-[#1e252b] [font-family:microsoft_yahei] md:h-[60dvh] md:min-h-[500px] md:w-[600px] md:rounded md:shadow"
      ref={forceElementRef}
    >
      <div className="flex justify-end text-white md:cursor-move" ref={ref}>
        <button
          className="group !border-none !bg-transparent p-2 !outline-none"
          onClick={onClickClose}
        >
          <CloseIcon className="transition-transform group-hover:scale-110" />
        </button>
      </div>
      <Home />
    </div>
  );
}
